
package cn.iocoder.yudao.framework.jackson.core;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.annotation.JacksonStdImpl;
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper;
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;

/**
 *  TODO 新增
 * <pre>
 * OOoO0OOoO0OOOooo0oOOOO0OOOOO0oooOO0ooOOO0Ooooo0OOOOo0ooooO0OOooo0Ooooo0OOOOO
 * 会将 {@link LocalTime} 序列化为毫秒级时间戳或指定格式的字符串
 * OOoO0OOoO0OOOooo0oOOOO0OOOOO0oooOO0ooOOO0Ooooo0OOOOo0ooooO0OOooo0Ooooo0OOOOO
 * </pre>
 *
 * @author 山野羡民（1032694760@qq.com）
 * @since 2024/05/12
 * @see com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer
 * @see cn.iocoder.yudao.framework.common.util.json.databind.TimestampLocalDateTimeSerializer
 */
@Slf4j
@JacksonStdImpl
public class EnhancedLocalTimeSerializer extends JsonSerializer<LocalTime> implements ContextualSerializer {
    public static final EnhancedLocalTimeSerializer INSTANCE = new EnhancedLocalTimeSerializer();
    private DateTimeFormatter formatter;

    private EnhancedLocalTimeSerializer() {
        log.trace("自定义 LocalTime 序列化，转成数字时间戳格式");
    }

    private EnhancedLocalTimeSerializer(DateTimeFormatter formatter) {
        this.formatter = formatter;
    }

    @Override
    public void serialize(LocalTime value, JsonGenerator g, SerializerProvider provider) throws IOException {
        if (formatter != null) {
            g.writeString(value.format(formatter));
        } else {
            long epochMilli = LocalDate.now().atTime(value).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
            log.trace("自定义 LocalTime 序列化，直接转为通用性更强更灵活的毫秒级时间戳格式，方便前端处理：{} -> {}", value, epochMilli);
            g.writeNumber(epochMilli);
        }
    }

    @Override
    public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) {
        if (property != null) {
            JsonFormat.Value format = prov.getAnnotationIntrospector().findFormat(property.getMember());
            if (format != null) {
                String pattern = format.getPattern();
                log.trace("使用自定义的 LocalTime 序列化器，使用指定格式：pattern={}", pattern);
                if (pattern != null && !pattern.isEmpty()) {
                    DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
                    return new EnhancedLocalTimeSerializer(formatter);
                }
            }
        }
        return this;
    }

    @Override
    public void acceptJsonFormatVisitor(JsonFormatVisitorWrapper visitor, JavaType typeHint) throws JsonMappingException {
        if (visitor != null) {
            if (formatter != null) {
                visitor.expectStringFormat(typeHint);
            } else {
                visitor.expectNumberFormat(typeHint);
            }
        }
    }

    @Override
    public void serializeWithType(LocalTime value, JsonGenerator gen, SerializerProvider serializers, TypeSerializer typeSer) throws IOException {
        if (formatter != null) {
            String formatted = value.format(formatter);
            gen.writeString(formatted);
        } else {
            long epochMilli = LocalDate.now().atTime(value).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
            gen.writeNumber(epochMilli);
        }
    }

}